package mutsumimod.patches;

import basemod.ReflectionHacks;
import com.evacipated.cardcrawl.mod.stslib.cards.targeting.SelfOrEnemyTargeting;
import com.evacipated.cardcrawl.modthespire.lib.*;
import com.evacipated.cardcrawl.modthespire.patcher.PatchingException;
import com.megacrit.cardcrawl.actions.utility.NewQueueCardAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.monsters.AbstractMonster;
import com.megacrit.cardcrawl.screens.CardRewardScreen;
import com.megacrit.cardcrawl.ui.buttons.SingingBowlButton;
import com.megacrit.cardcrawl.vfx.SpeechBubble;
import javassist.CannotCompileException;
import javassist.CtBehavior;
import mutsumimod.effect.LateQueueCardEffect;
import mutsumimod.cards.BaseCard;
import mutsumimod.monitors.CopyMonitor;
import mutsumimod.powers.MultiHeadPower;

import java.util.ArrayList;

public class CardRewardScreenPatch extends BasePatch {

    @SpirePatch(
            clz = CardRewardScreen.class,
            method = SpirePatch.CLASS
    )
    public static class CardRewardScreenFieldPatch {
        public static SpireField<Boolean> isCopyChooseOne = new SpireField<>(() -> false);
    }

    //主要针对觉醒者
    public static boolean isNoMonsterCanSelect(){
        for(AbstractMonster m : AbstractDungeon.getMonsters().monsters){
            if(!m.isDeadOrEscaped()){
                return false;
            }
        }
        return true;
    }

    @SpirePatch(
            clz = CardRewardScreen.class,
            method = "cardSelectUpdate"
    )
    public static class cardSelectUpdatePatch {
        @SpireInsertPatch(
                locator = Locator.class,
                localvars = {"hoveredCard"}
        )
        public static SpireReturn insert(CardRewardScreen __instance,AbstractCard hoveredCard) {
            if(CardRewardScreenFieldPatch.isCopyChooseOne.get(__instance)) {

                boolean isUsed=false;
                for(AbstractCard c:__instance.rewardGroup){
                    if(c.equals(hoveredCard)){
                        if(c.canUse(AbstractDungeon.player,null)){
                            if(c.target.equals(AbstractCard.CardTarget.ENEMY)){
                                if(isNoMonsterCanSelect()){
                                    AbstractDungeon.effectList.add(new SpeechBubble(AbstractDungeon.player.dialogX,
                                            AbstractDungeon.player.dialogY, 1.0f, "没有可以攻击的目标", true));
                                }else{
                                    CopyMonitor.setCopyCard(c);
                                }
                            }else if(c.target.equals(SelfOrEnemyTargeting.SELF_OR_ENEMY)) {
                                CopyMonitor.setCopyCard(c);
                            }else{
                                addToBot(new NewQueueCardAction(c,true,true,true));
                            }
                            isUsed=true;
                        }else{
                            AbstractDungeon.effectList.add(new SpeechBubble(AbstractDungeon.player.dialogX,
                                    AbstractDungeon.player.dialogY, 1.0f, "不能打出此牌", true));
                        }
                    }
                }

                if(isUsed){
                    AbstractCard choosedCard=null;
                    ArrayList<AbstractCard> notChoosedCards=new ArrayList<>();
                    for(AbstractCard c:__instance.rewardGroup){
                        if(!c.equals(hoveredCard)){
                            notChoosedCards.add(c);
                        }else{
                            choosedCard=c;
                        }
                    }

                    for(AbstractCard c:__instance.rewardGroup){
                        AbstractCard originCard=CopyPatch.AbstractCardFieldPatch.originCard.get(c);
                        if(c.equals(hoveredCard)){
                            if(originCard instanceof BaseCard){
                                ((BaseCard) originCard).onCopyChooseThisCard(notChoosedCards);
                            }
                        }else{
                            if(AbstractDungeon.player.hasPower(MultiHeadPower.POWER_ID)){
                                AbstractDungeon.effectList.add(new LateQueueCardEffect(c));
                            }
                            if(originCard instanceof BaseCard){
                                ((BaseCard) originCard).onCopyNotChooseThisCard(choosedCard);
                            }
                        }
                    }

                    CardRewardScreenFieldPatch.isCopyChooseOne.set(__instance,false);

                    ReflectionHacks.privateMethod(CardRewardScreen.class,"takeReward")
                            .invoke(__instance);
                    AbstractDungeon.closeCurrentScreen();
                    ReflectionHacks.setPrivate(__instance, CardRewardScreen.class, "draftCount", 0);
                }

                return SpireReturn.Return();
            }
            return SpireReturn.Continue();
        }

        private static class Locator extends SpireInsertLocator {
            public int[] Locate(CtBehavior ctMethodToPatch) throws CannotCompileException, PatchingException {
                Matcher finalMatcher = new Matcher.MethodCallMatcher(SingingBowlButton.class, "hide");

                int[] lines = LineFinder.findInOrder(ctMethodToPatch, new ArrayList<Matcher>(), finalMatcher);
                return new int[]{lines[0]+1};
            }
        }
    }


    @SpirePatch(
            clz = AbstractCard.class,
            method = "canUse",
            paramtypez = {
                    AbstractPlayer.class, AbstractMonster.class
            }
    )
    public static class CanUseFixPatch {
        @SpireInsertPatch(
                locator = Locator.class
        )
        public static SpireReturn<Boolean> insert(AbstractCard __instance){
            if(CopyPatch.AbstractCardFieldPatch.inCopyUse.get(__instance)){
                return SpireReturn.Return(true);
            }
            return SpireReturn.Continue();
        }

        private static class Locator extends SpireInsertLocator {
            public int[] Locate(CtBehavior ctMethodToPatch) throws CannotCompileException, PatchingException {
                Matcher finalMatcher = new Matcher.MethodCallMatcher(AbstractCard.class, "cardPlayable");

                int[] lines = LineFinder.findInOrder(ctMethodToPatch, new ArrayList<Matcher>(), finalMatcher);
                return new int[]{lines[0]};
            }
        }
    }
}
